﻿#region --- License & Copyright Notice
/*
CRUD Services Library

Copyright 2012 Jeevan James

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#endregion

using System;

namespace CrudServices
{
    public class SearchCriteriaBuilder
    {
        private readonly SearchCriteria _criteria;

        protected SearchCriteria Criteria
        {
            get { return _criteria; }
        }

        internal SearchCriteriaBuilder(string source)
        {
            if (source == null)
                throw new ArgumentNullException("source");
            _criteria = new SearchCriteria(source);
        }

        public SearchCriteriaBuilder OrderBy(params string[] fieldNames)
        {
            foreach (string fieldName in fieldNames)
                _criteria.SortFields.Add(new SortCriterion(fieldName));
            return this;
        }

        public SearchCriteriaBuilder OrderByDescending(params string[] fieldNames)
        {
            foreach (string fieldName in fieldNames)
                _criteria.SortFields.Add(new SortCriterion(fieldName, SortOrder.Descending));
            return this;
        }

        public SearchCriteria Select<TTarget>()
        {
            _criteria.ProjectionTarget = typeof(TTarget).Name;
            return _criteria;
        }

        public SearchCriteria SelectAll()
        {
            return _criteria;
        }

        public SearchCriteriaBuilder Skip(int skip)
        {
            if (_criteria.Skip.HasValue)
                throw new InvalidOperationException("Cannot specify Skip more than once");
            _criteria.Skip = skip;
            return this;
        }

        public SearchCriteriaBuilder Limit(int limit)
        {
            if (_criteria.Limit.HasValue)
                throw new InvalidOperationException("Cannot specify Limit more than once");
            _criteria.Limit = limit;
            return this;
        }

        public SearchCriteriaBuilder Where<TValue>(string fieldName, WhereOperand operand, TValue value)
        {
            if (value == null)
            {
                if (operand == WhereOperand.Equals)
                    operand = WhereOperand.IsNull;
                else if (operand == WhereOperand.DoesNotEqual)
                    operand = WhereOperand.NotNull;
                else
                    throw new NotSupportedException("Cannot use operand " + operand + " with a null value");
            }
            _criteria.WhereCriteria.Add(new WhereCriterion(fieldName, operand, value != null ? value.ToString() : null));
            return this;
        }

        public static SearchCriteriaBuilder From(string source)
        {
            return new SearchCriteriaBuilder(source);
        }

        public static SearchCriteriaBuilder<TEntity> From<TEntity>()
        {
            return new SearchCriteriaBuilder<TEntity>();
        }
    }
}